package com.qd.core.service;

import com.cdqidi.core.weixinmanager.event.WxMiddleUserUpdateEvent;
import com.cdqidi.core.weixinmanager.model.MiddleUser;
import com.cdqidi.core.weixinmanager.service.MiddleUserService;
import com.cdqidi.util.JacksonUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.qd.common.sys.domain.entity.log.ReceiveLogDTO;
import com.qd.common.sys.domain.entity.log.SendLogDTO;
import com.qd.common.sys.domain.entity.login.LoginUserDTO;
import com.qd.common.sys.domain.entity.login.LoginUserOrgDTO;
import com.qd.common.sys.domain.event.OperatorDTO;
import com.qd.common.sys.domain.login.LoginLogDTO;
import com.qd.common.sys.domain.login.LoginStatusDTO;
import com.qd.common.sys.domain.login.LoginUser;
import com.qd.common.sys.event.*;
import com.qd.core.dblog.LogProcess;
import com.qd.system.model.LoginLog;
import com.qd.system.model.LoginUserOrg;
import com.qd.system.model.OperatorLog;
import com.qd.system.service.article.ArticleService;
import com.qd.system.service.log.OperatorLogService;
import com.qd.system.service.log.ReceiveLogService;
import com.qd.system.service.log.SendLogService;
import com.qd.system.service.login.LoginUserOrgService;
import com.qd.system.service.login.LoginUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * 异步处理
 *
 * @author sjk
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class SystemAsyncService {
    private final LoginUserService loginUserService;
    private final OperatorLogService operatorLogService;
    private final LoginUserOrgService loginUserOrgService;
    private final ArticleService articleService;
    @Resource
    private MiddleUserService middleUserService;
    private final SendLogService sendLogService;
    private final ReceiveLogService receiveLogService;

    /**
     * 修改用户的登录状态
     *
     * @param event 登录状态信息
     */
    @Async
    @Transactional(rollbackFor = Exception.class)
    @EventListener(classes = LoginStatusEvent.class)
    public void updateLoginUserStatus(LoginStatusEvent event) {
        final LoginStatusDTO loginStatus = (LoginStatusDTO) event.getSource();
        final com.qd.system.model.LoginUser loginUser = loginUserService.selectUserByUserName(loginStatus.getAccount());
        loginUser.setState(loginStatus.getLoginStatus());
        loginUserService.updateById(loginUser);
        log.info("修改用户登录状态,account: {},status: {}", loginUser.getAccount(), loginStatus.getLoginStatus());
        loginStatus.freeData();
    }

    /**
     * 记录登录/退出日志
     *
     * @param event 登录信息
     */
    @Async
    @EventListener(classes = LoginUserLogEvent.class)
    public void saveLog(LoginUserLogEvent event) {
        final LoginLogDTO loginLogDto = (LoginLogDTO) event.getSource();
        final LoginLog loginLog = new LoginLog();
        final LoginUser loginUser = loginLogDto.getLoginUser();
        final LoginUserDTO user = loginUser.getUser();
        if (null != user) {
            loginLog.setUserId(user.getPersonId());
            if (StringUtils.hasLength(user.getPersonName())) {
                loginLog.setUserName(user.getPersonName());
            }
            loginLog.setOrgId(user.getOrgId());
            loginLog.setOrgName(user.getOrgIdDisplay());
        }
        loginLog.setAccount(loginUser.getUsername());
        loginLog.setStatus(loginLogDto.getStatus());
        loginLog.setMessage(loginLogDto.getMessage());
        loginLog.setLoginTime(LocalDateTime.now());
        loginLog.setBrowser(loginUser.getBrowser());
        loginLog.setOs(loginUser.getOs());
        loginLog.setUserIp(loginUser.getIpaddr());
        LogProcess.getInstance().addLoginLog(loginLog);
        //loginLogService.save(loginLog);
        //log.info("保存用户登录信息,account: " + loginLog.getAccount() + ",status: " + loginLogDto.getStatus());
        //loginLog.freeData();
    }

    /**
     * 记录操作日志
     *
     * @param event 日志信息
     */
    @Async
    @EventListener(classes = OperatorLogEvent.class)
    public void saveOperatorLog(OperatorLogEvent event) throws JsonProcessingException {
        final OperatorDTO operatorDTO = (OperatorDTO) event.getSource();
        final OperatorLog operatorLog = operatorLogService.dtoToModel(operatorDTO.getOperatorLog());
        final long time = operatorDTO.getEndTime() - operatorDTO.getStartTime();
        operatorLog.setInterfaceTime(time);
        if (StringUtils.hasLength(operatorDTO.getRequestParam())) {
            operatorLog.setRequestParam(operatorDTO.getRequestParam());
        }
        if (null != operatorDTO.getResponseParam()) {
            operatorLog.setResultParam(JacksonUtil.getObjectMapper().writeValueAsString(operatorDTO.getResponseParam()));
        }
        operatorLog.setOperatorTime(LocalDateTime.now());
        //operatorLogService.save(operatorLog);
        //operatorDto.freeData();
        //log.info("记录用户操作日志");
        LogProcess.getInstance().addOperatorLog(operatorLog);
    }

    /**
     * 设置登录用户所属机构
     *
     * @param event 用户和机构关系
     */
    @Async
    @Transactional(rollbackFor = Exception.class)
    @EventListener(classes = LoginUserOrgEvent.class)
    public void saveLoginUserOrg(LoginUserOrgEvent event) {
        final LoginUserOrgDTO dto = (LoginUserOrgDTO) event.getSource();
        final LoginUserOrg loginUserOrg = loginUserOrgService.getUniqueByPersonIdAndRemote(dto.getPersonId(), dto.getRemote());
        if (null == loginUserOrg) {
            loginUserOrgService.save(dto);
            log.info("设置登录用户所属机构,personId: {},orgId: {}", dto.getPersonId(), dto.getOrgId());
            dto.freeData();
            return;
        }
        if (!loginUserOrg.getOrgId().equals(dto.getOrgId())) {
            dto.setId(loginUserOrg.getId());
            loginUserOrgService.update(dto);
            log.info("更新登录用户所属机构,personId: {},orgId: {}", dto.getPersonId(), dto.getOrgId());
            dto.freeData();
        }
    }

    /**
     * 增加文章点击数
     *
     * @param event 用户和机构关系
     */
    @Async
    @Transactional(readOnly = true)
    @EventListener(classes = ArticleHintCountEvent.class)
    public void addHintCount(ArticleHintCountEvent event) {
        String articleId = (String) event.getSource();
        articleService.addHintCount(articleId);
    }

    /**
     * 更新微信和用户绑定关系信息
     *
     * @param event 用户在微信的unionId
     */
    @Async
    @Transactional(rollbackFor = Exception.class)
    @EventListener(classes = WxMiddleUserUpdateEvent.class)
    public void updateWxMiddleUser(WxMiddleUserUpdateEvent event) {
        MiddleUser middleUser = (MiddleUser) event.getSource();
        middleUserService.updateById(middleUser);
        middleUserService.clearCache(middleUser);
        middleUser.freeData();
    }

    /**
     * 发送日志
     */
    @Async
    @EventListener(classes = SendLogEvent.class)
    public void addSendLog(SendLogEvent event) {
        SendLogDTO sendLogDTO = (SendLogDTO) event.getSource();
        LogProcess.getInstance().addSendLog(sendLogService.dtoToModel(sendLogDTO));
        sendLogDTO.freeData();
    }

    /**
     * 接收日志
     */
    @Async
    @EventListener(classes = ReceiveLogEvent.class)
    public void addReceiveLog(ReceiveLogEvent event) {
        ReceiveLogDTO receiveLogDTO = (ReceiveLogDTO) event.getSource();
        LogProcess.getInstance().addReceiveLog(receiveLogService.dtoToModel(receiveLogDTO));
        receiveLogDTO.freeData();
    }
}